function fn() {
	// 存储执行fn传递的实参信息
	let outer = Array.from(arguments)
	return function anonymous() {
		// 存储执行小函数传递的实参信息
		let inner =  Array.from(arguments)

        // 存储两次执行函数传递的实参信息
        let params = outer.concat(inner) // [1, 2, 3]
        return params.reduce((res, item) => res += item)
	}
}
const fn2 = (...outer) => {
    return (...innner) => {
        return outer.concat(innner).reduce((res, item) => res + item) 
    }
}
let res = fn(1, 2)(3)
// console.log(res) // 6
let res2 = fn2(1, 2)(3)
// console.log(res2); // 6
/*
 1. fn传的是1和2，fn执行形成私有上下文，返回一个函数（堆地址），把返回的函数紧接着执行一次，当前形成的上下文不能释放，
 传递进来的1和2先在outer中存下来，我们要实现的是新传的值和之前的值累加，要用到之前的值通过作用域链向上级上下文查找存
 的值，预处理的思想【预先存储，后续拿来直接用】
*/

// 数组中的reduce
let arr = [10, 20, 30, 40]
let result = arr.reduce((res, item) => res += item) 
// console.log(result);// 100

// 数组中的reduce： 依次遍历数组中的每一项，可以把上一轮遍历得到的结果，传递给下一轮，以实现结果的累计
// arr.reduce([function]) 会把数组的第一项做为初始结果，从数组第二项开始遍历
// arr.reduce([function], [value])：第二个传递的参数作为初始结果，从数据的第一项开始遍历
let result2 = arr.reduce(function (result, item, index) {
    // 第一轮遍历： result -> 10 item -> 20 index -> 1
    // 第二轮遍历： result -> 30 [上一轮遍历， 函数返回的结果] item -> 30 index -> 2
    // 第三轮遍历:  result -> 60 item -> 40 index -> 2
    // console.log(result, item, index);
    // return result + item
})
// arr.reduce([function], [value])：第二个传递的参数作为初始结果，从数据的第一项开始遍历
let result3 = arr.reduce(function (result, item, index) {
    /* let arr = [10, 20, 30, 40]
    0 10 0
    10 20 1
    30 30 2
    60 40 3
     */
    // console.log(result, item, index);
    // return result + item
}, 0)

// 手写reduce
// callback 回调函数，把一个函数作为实参值， 传递给另外一个函数  // arr.forEach(function(){}) setTimeout(function(){}, 1000)
function reduce(arr, callback, initValue) {
    let result = initValue, i = 0
    // 没有传递initValue初始值： 把数组第一项作为初始值，遍历从数组第二项开始
    if (typeof result === 'undefined') {
        result = arr[0]
        i = 1
    }
    // 遍历数组中的每一项： 每一次遍历都会把callback执行
    for (; i < arr.length; i++) {
        result = callback(result, arr[i], i)
    }
    return result
}
let arr4 = [10, 20, 30, 40]
let result4 = reduce(arr4, (result, item, index) => result += item)
// console.log(result4);

/*
 柯里化函数(预处理的思想)
 执行函数，形成一个闭包，把一些信息（私有变量和值）存储起来【保存作用】
 以后其下级上下文中如果需要用到这些值， 直接基于作用域链查找机制，拿来直接可以用
*/

// leetcode 例题
/* LCP 06. 拿硬币
https://leetcode-cn.com/problems/na-ying-bi/
桌上有 n 堆力扣币，每堆的数量保存在数组 coins 中。我们每次可以选择任意一堆，拿走其中的一枚或者两枚，求拿完所有力扣币的最少次数。
输入：[4,2,1]
输出：4
*/
var minCount = function(coins) {
    return coins.reduce((res, item) => res += Math.ceil(item / 2), 0)
};
// console.log(minCount([4,2,1])); //4

/*462. 最少移动次数使数组元素相等 II
给定一个非空整数数组，找到使所有数组元素相等所需的最小移动数，其中每次移动可将选定的一个元素加1或减1。 您可以假设数组的长度最多为10000。
输入:
[1,2,3]
输出:
2
说明：
只有两个动作是必要的（记得每一步仅可使其中一个元素加1或减1）： 
[1,2,3]  =>  [2,2,3]  =>  [2,2,2]

// arr.reduce([function], [value])：第二个传递的参数作为初始结果，从数据的第一项开始遍历
对给定的数组进行排序
使用双指针，left 指向 index=0，right 指向 index=nums.length-1
对左右指针指向的数进行绝对值求差
左右指针往中心靠拢
处理左右指针在中心处的特殊情况
左右指针重叠
左右指针相邻
0 1
1 2
1 3
*/
var minMoves2 = function (nums) {
    nums.sort((a, b) => a - b)
    let avg = nums[Math.ceil(nums.length / 2) - 1]
    return nums.reduce((res, item) => {
        console.log(res, item);
        return res + Math.abs(item - avg)
    }, 0)
};
// console.log(minMoves2([1,2,3]));

// var minMoves2 = function (nums) {
//     nums.sort((a, b) => a - b)
//     let avg = nums[Math.ceil(nums.length / 2) - 1]
//     return nums.reduce((res, item) => res + Math.abs(item - avg), 0)
// };

var reverseString = function (s) {
    return s.reduceRight((t, v) => t + v).split('')
};
console.log(reverseString(["h","e","l","l","o"]));

// 205. 同构字符串 https://leetcode-cn.com/problems/isomorphic-strings/
// 输入：s = "egg", t = "add"
// 输出：true
var isIsomorphic = function(s, t) {
    return s.split('').reduce( (res, ele, i) => 
     s.indexOf(s[i]) == t.indexOf(t[i]) ? res : false)
};
console.log(isIsomorphic(s = "egg", t = "add"));

// 217. 存在重复元素 https://leetcode-cn.com/problems/contains-duplicate/
// 输入: [1,2,3,1]
// 输出: true
var containsDuplicate = function(nums) {
    let obj = nums.reduce((a,b) => (a[b]++ || (a[b] =1),a),{})
    let flag = false
    Object.keys(obj).forEach( i => {
        if (obj[i] > 1) flag = true
    })
    return flag
  };


//   https://juejin.cn/post/6844904063729926152#heading-2
// 代替map：[0, 2, 4, 6]
const a = arr.map(v => v * 2);
const b = arr.reduce((t, v) => [...t, v * 2], []);

// 代替filter：[2, 3]
const c = arr.filter(v => v > 1);
const d = arr.reduce((t, v) => v > 1 ? [...t, v] : t, []);

// 代替map和filter：[4, 6]
const e = arr.map(v => v * 2).filter(v => v > 2);
const f = arr.reduce((t, v) => v * 2 > 2 ? [...t, v * 2] : t, []);

const scores = [
    { score: 45, subject: "chinese" },
    { score: 90, subject: "math" },
    { score: 60, subject: "english" }
];

// 代替some：至少一门合格
const isAtLeastOneQualified = scores.reduce((t, v) => t || v.score >= 60, false); // true

// 代替every：全部合格
const isAllQualified = scores.reduce((t, v) => t && v.score >= 60, true); // false

// 数组过滤
function Difference(arr = [], oarr = []) {
    return arr.reduce((t, v) => (!oarr.includes(v) && t.push(v), t), []);
}
const arr1 = [1, 2, 3, 4, 5];
const arr2 = [2, 3, 6]
Difference(arr1, arr2); // [1, 4, 5]

// 数组扁平
function Flat(arr = []) {
    return arr.reduce((t, v) => t.concat(Array.isArray(v) ? Flat(v) : v), [])
}
const arr = [0, 1, [2, 3], [4, 5, [6, 7]], [8, [9, 10, [11, 12]]]];
Flat(arr); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

// 数组去重
function Uniq(arr = []) {
    return arr.reduce((t, v) => t.includes(v) ? t : [...t, v], []);
}
const arr = [2, 1, 0, 3, 2, 1, 2];
Uniq(arr); // [2, 1, 0, 3]

// 数组最大最小值
function Max(arr = []) {
    return arr.reduce((t, v) => t > v ? t : v);
}

function Min(arr = []) {
    return arr.reduce((t, v) => t < v ? t : v);
}
